use std::{
    collections::HashMap,
    sync::{atomic::AtomicU64, Arc, LazyLock},
};

use async_trait::async_trait;
use log::warn;
use parking_lot::RwLock;
use tokio::io::AsyncWriteExt;

use crate::{listener::ArcListener, stream::Stream};

#[allow(dead_code)]
#[async_trait]
pub trait AppHandle: Sync + Send {
    async fn handle(&self, event: Stream, listener: ArcListener);
}

pub type AppHandleIface = Box<dyn AppHandle>;

pub struct EmptyAppHandle {}

pub static COUNTER: AtomicU64 = AtomicU64::new(0);

#[async_trait]
impl AppHandle for EmptyAppHandle {
    async fn handle(&self, mut event: Stream, listener: ArcListener) {
        warn!(
            "empty handle callback, listener address: {}, counter: {}",
            listener.get_conf().address,
            COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
        );

        _ = event.shutdown().await;
    }
}

pub struct AppManager {
    apps: RwLock<HashMap<String, Arc<AppHandleIface>>>,
}

#[allow(dead_code)]
impl AppManager {
    pub fn get_instance() -> &'static AppManager {
        static APP_MANAGER: LazyLock<AppManager> =
            LazyLock::new(|| AppManager {
                apps: RwLock::new(HashMap::new()),
            });

        &APP_MANAGER
    }

    pub fn register_app(app_name: String, handle: Arc<AppHandleIface>) {
        let instance = Self::get_instance();
        let mut guard = instance.apps.write();
        let res = guard.insert(app_name, handle);
        if res.is_some() {
            panic!("Duplicate registration of the app");
        }
    }

    pub fn get_app_handle(app_name: &String) -> Arc<AppHandleIface> {
        let instance = Self::get_instance();
        let guard = instance.apps.read();
        let res = guard.get(app_name);
        if let Some(r) = res {
            return r.clone();
        }

        Arc::new(Box::new(EmptyAppHandle {}))
    }
}
